#include "utils.hpp"

namespace bp
{  
   
clPaths Paths;
clLog Log(Paths.ObtieneRuta("Log_PATH"));
  
using namespace std;

clLog::clLog(const char* ruta)
{
  m_Log.open(ruta);
  
}

void clLog::Add(std::string tx)
{
  stringstream io;
  io << "[" << SDL_GetTicks() << "] " << tx << endl;
  m_Log << io.str();
  io.str("");  
}

clLog::~clLog()
{
  m_Log.close();
}


clPaths::clPaths()
{
	m_ruta_raiz = DefineRutaRaiz();
    CargaRutas();
}

void clPaths::CargaRutas()
{
	Buffer_t RutaConf;
	RutaConf << m_ruta_raiz << m_sep << "config" << m_sep << "rutas.cfg";
	std::fstream in(RutaConf.str().c_str());
	if (in.is_open())
    {
        string line;
        while (in.good())
        {
            getline(in, line);
			if (line.empty()) continue;
			if (line[0] == '#') continue;
				size_t pos = line.find_last_of("\t");
			m_conf_rutas[line.substr(0, pos)] = m_ruta_raiz + m_sep + line.substr(pos+1, line.size());
        }
        in.close();        
    }    
}


std::string clPaths::DefineRutaRaiz()
{
	Str_t ruta_raiz = utl::file::CurrentDir();
	if (ruta_raiz.empty()) return m_ruta_raiz;
	m_sep = utl::file::GetDirSep();
	size_t pos = 0;
	while ( ( pos = ruta_raiz.find_last_of(m_sep) ) != Str_t::npos )
	{
		ruta_raiz = ruta_raiz.substr(0, pos);
        VFile_t lista;
		utl::file::ListDir(ruta_raiz.c_str(), utl::file::todos, lista);
		VFile_t::iterator it;
		for(it = lista.begin(); it != lista.end(); it++) 
		{
		  if (it->name.compare("imagenes") == 0) return ruta_raiz;
		}
        if (it != lista.end()) break;
	}
	return ruta_raiz;
}

const char* conv::sdlkeytostring(int32_t key)
{
  if (key == SDLK_ESCAPE)
	return TO_STRING(SDLK_ESCAPE);
  
  else if (key == SDLK_LEFT)
	return TO_STRING(SDLK_LEFT);
  
  else if (key == SDLK_RIGHT)
	return TO_STRING(SDLK_RIGHT);
  
  else if (key == SDLK_UP)
	return TO_STRING(SDLK_UP);
  
  else if (key == SDLK_DOWN)
	return TO_STRING(SDLK_DOWN);
  
  else if (key == SDLK_a)
	return TO_STRING(SDLK_a);
  
  else if (key == SDLK_s)
	return TO_STRING(SDLK_s);
  
  else if (key == SDL_KEYDOWN)
	return TO_STRING(SDL_KEYDOWN);
  
  else if (key == SDL_KEYUP)
	return TO_STRING(SDL_KEYUP);  
  
  else if (key == SDLK_SPACE)
	return TO_STRING(SDLK_SPACE);
  
  else if (key == SDLK_LCTRL)
	return TO_STRING(SDLK_LCTRL);	
  
  else
	return "N/S";
}

namespace utl
{
	
namespace file
{
	bool Split(CoChar_t& sep, CoCStr_t raw, VStr_t& split_values)
	{
		Str_t line(raw);
		size_t pos = 0;
		while((pos = line.find_first_of(sep)) != std::string::npos)
		{
			split_values.push_back(line.substr(0, pos));
			line = line.substr(pos+1, line.size());
		}
		split_values.push_back(line);
		if (split_values.size() == 0) return false;

		return true;
	}

	CoStr_t CurrentDir(void)
	{
		char rawDir[FILENAME_MAX];
		GetCurrentDir(rawDir, FILENAME_MAX);			
		return std::string(rawDir).c_str();
	}

	uint32_t NumOfDirLevels(void)
	{			
		VStr_t dirs;			
		Split(GetDirSep(), CurrentDir().c_str(), dirs);
		return static_cast<uint32_t>(dirs.size());
	}

	/* ------------------------------------------------------------------------------------------------
	DIRLEVEL(CInt_t& Level, Str_t& Dir)
	* Si tenemos el Directorio C:\uno\dos\tres\cuatro y queremos obtener la ruta hasta C:\uno\dos
	* le pasamos (NºNIVELES - 2), es decir, dos niveles arriba
	* Ej:
	* Str_t& Dir;
	* DirLevel(NumOfDirLevels() - 2, Dir);
	* ------------------------------------------------------------------------------------------------*/
	CoStr_t DirLevel(const size_t& Level)
	{
		VStr_t dirs;
		Str_t Dir;
		Split(GetDirSep(), CurrentDir().c_str(), dirs);
		if (Level > 0 && Level < dirs.size())			
		{
			Dir.clear();
			size_t i = 0;
			for(VStr_t::iterator it = dirs.begin(); i < Level && it != dirs.end(); it++, i++)				
			{
				if (it == dirs.begin())
					Dir.append(*it);				
				else
					Dir.append(GetDirSep() + *it);				
			}
		}
		return Dir.c_str();
	}

	Char_t GetDirSep(void)
	{			
		Str_t like_unix = CurrentDir().substr(0, 1);
		Str_t like_win  = CurrentDir().substr(1, 2);

		if ( like_unix.compare("/") == 0 )
			return '/';
		else if ( like_win.compare(":\\") == 0 ) 
			return '\\';
		
		return '#';

	}

	CoStr_t FixWinPath(CoCStr_t path)
	{
		size_t len = std::string(path).size();
		if (len == 0) return "";
		Str_t n_path;
		n_path.resize(len+1);
		char* c_str = new char[len+1];		
		memset(c_str, 0, len+1);
		strncpy(c_str, path, len);		
		uint32_t x = 0;
		for(uint32_t i = 0; i < len; i++)
		{
			if (*(c_str+i) == '\\' && *(c_str+i+1) != '\\')
			{
				n_path.resize(n_path.size()+1);
				n_path[x++] = '\\';
			}
			n_path[x++] = *(c_str+i);
		}
		delete[] c_str;
		c_str = NULL;

		return n_path;
	}

	CoStr_t ExtractExt(CoCStr_t path)
	{
		return std::string(path).substr(std::string(path).find_last_of(".")+1, std::string(path).size()).c_str();
	}	

	bool ListDir(CoCStr_t path, CoUInt_t filter, VFile_t& list)
	{
		DirDetail_t ent = NULL;
		Dir_t dir = opendir(path);
		File_t listDetail;
		if (dir != NULL) 
		{
			while ((ent = readdir (dir)) != NULL) 
			{
				switch (ent->d_type) 
					{
					case DT_REG:	// Ficheros
						if (filter == fichero || filter == todos)
						{
							listDetail.type = fichero;
							listDetail.name = std::string(ent->d_name);
						}
					  break;

					case DT_DIR:	// Directorios		  
						if (std::string(ent->d_name).compare(".") == 0 || std::string(ent->d_name).compare("..") == 0)
							continue;
						if (filter == directorio || filter == todos)
						{
							listDetail.type = directorio;
							listDetail.name = std::string(ent->d_name);
						}
					  break;

					default:		// Otros
						if (filter == otros || filter == todos)
						{
							listDetail.type = otros;
							listDetail.name = std::string(ent->d_name);
						}					  
					}
				list.push_back(listDetail);
			}
		} else return false;

		closedir (dir);
		return true;
	}

	bool RemoveFile(CoCStr_t path)
	{
		return (remove(path) == 0) ? true : false;
	}



	bool ExistDir(CoCStr_t path)
	{
		DirDetail_t ent = NULL;
		Dir_t dir = opendir(path);		
		if (dir == NULL) return false;
		if ((ent = readdir (dir)) == NULL) return false;
		if (ent->d_type != DT_DIR) return false;

		return true;
	}

	bool CreateDir(CoCStr_t path)
	{
		if (ExistDir(path)) return false;
		return (mkdir(path) == 0) ? true : false;
	}

	bool ReadTxFile(CoCStr_t path, Str_t& content)
	{
		std::ifstream fileInput(path);
		if (fileInput.is_open())
		{            
			Str_t line;
			fileInput.seekg(0, std::ios::beg);
			Buffer_t ss;
			ss << fileInput.rdbuf();
			content = ss.str();
			fileInput.close();
			if (content.size() == 0) return false;

		} else return false;

		return true;
	}

	bool ReadBinFile(CoCStr_t path, Str_t& content)
	{
		std::ifstream BinFile(path, std::ios::in | std::ios::binary | std::ios::ate);
		std::ifstream::pos_type fileSize = 0;
		CStr_t fileContents = NULL;
		if (BinFile.is_open())
		{
			fileSize = BinFile.tellg();
			fileContents = new char[static_cast<int>(fileSize)];
			BinFile.seekg(0, std::ios::beg);
			if (!BinFile.read(fileContents, static_cast<std::streamsize>(fileSize) )) 
			{
				delete[] fileContents;
				fileContents = NULL;
				return false;
			}
			BinFile.close();
			content.append(fileContents, static_cast<size_t>(fileSize) );
			delete[] fileContents;
			fileContents = NULL;		
		} else return false;

		return true;  
	}

} // namespace file

namespace sys
{
		
	bool ExecCmd(CoCStr_t cmd)
	{
		std::printf("Begining to Execute Command...");	
		Str_t lcmd(cmd);		
		#ifdef WIN		
			CoCStr_t co_cmd = "cmd.bat";
			std::ofstream fileOut(co_cmd);
			if (fileOut.is_open())
			{
				fileOut << lcmd;
				fileOut.close();		
				lcmd = co_cmd;
				fileOut.close();				
			} else return false;
		#endif
		system(lcmd.c_str());	

		return true;
	}

} // namespace sys



} // namespace utl



} // namespace bp
